package com.yeskery.boot.log.record.starter.parser;

import com.yeskery.boot.log.record.starter.core.LogRecordOperationSource;
import com.yeskery.boot.log.record.starter.core.StatementType;
import com.yeskery.boot.log.record.starter.core.LogRecordOps;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.expression.AnnotatedElementKey;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionException;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Method;

/**
 * 日志记录解析类
 * @author dushuangjiang
 * @date 2021-11-16 17:57
 */
public class LogRecordValueParser {

    private static final Log log = LogFactory.getLog(LogRecordValueParser.class);

    private final LogRecordExpressionEvaluator expressionEvaluator = new LogRecordExpressionEvaluator();

    private final IFunctionService functionService;

    private final LogRecordOperationSource logRecordOperationSource;

    /**
     * 构建日志记录解析类对象
     * @param functionService 日志记录解析类对象
     */
    public LogRecordValueParser(IFunctionService functionService, LogRecordOperationSource logRecordOperationSource) {
        this.functionService = functionService;
        this.logRecordOperationSource = logRecordOperationSource;
    }

    /**
     * 解析表达式
     * @param logRecordOps 日志操作对象
     * @param method 方法
     * @param targetClass 目标类
     * @param evalContext 解析上下文对象
     * @return 解析后的值
     */
    public String parse(LogRecordOps logRecordOps, Method method, Class<?> targetClass, EvaluationContext evalContext) {
        if (logRecordOps.getStatementType() == StatementType.SpEL) {
            try {
                return parseSpElExpression(logRecordOps.getStatement(), method, targetClass, evalContext);
            } catch (ExpressionException e) {
                log.error("SpEL execution failed", e);
                return "";
            }
        }
        if (!CollectionUtils.isEmpty(logRecordOps.getDependencies())) {
            for (LogRecordOps recordOps : logRecordOps.getDependencies()) {
                String value = parse(recordOps, method, targetClass, evalContext);
                logRecordOps.setStatement(logRecordOps.getStatement().replace(recordOps.getStatement(), value));
            }
        }
        return functionService.apply(logRecordOps.getFunctionName(), logRecordOperationSource.findFunctionExecuteValue(logRecordOps));
    }

    /**
     * 解析SpEL表达式
     * @param expression SpEL表达式
     * @param method 方法
     * @param targetClass 目标类
     * @param evalContext 解析上下文对象
     * @return 解析后的值
     */
    private String parseSpElExpression(String expression, Method method, Class<?> targetClass, EvaluationContext evalContext) {
        return expressionEvaluator.parseExpression(expression, new AnnotatedElementKey(method, targetClass), evalContext);
    }
}
